package com.gopay.bis.nucc.common.util;


import com.gopay.bis.common.util.BankLogUtils;
import com.gopay.common.cipher.utils.LoggerMaskUtils;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.domain.bank.BaseMessage;
import com.gopay.common.domain.bank.nucc.bcdl.eft.req.NuccBcdlBodyPyeeAcctInf;
import com.gopay.common.domain.bank.nucc.bcdl.eft.req.NuccBcdlBodyPyerInf;
import com.gopay.common.domain.bank.nucc.bcdl.eft.req.NuccBcdlBodyReq;
import com.gopay.common.domain.bank.nucc.common.base.NuccBaseHeaderMessage;
import com.gopay.common.domain.bank.nucc.common.base.NuccBaseMessage;
import com.gopay.common.exception.GopayException;
import com.thoughtworks.xstream.XStream;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;


/** 
 * 网联安全工具类
 * @ClassName: NuccCertHelper
 * @author zhoutong
 * @date 2018年1月15日 下午5:31:41
 */ 
public class NuccCertHelper {

    /**
     * 日志
     */
    private static Logger logger = LoggerFactory.getLogger(NuccCertHelper.class);


    private final static String XML_HEADER = "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>";

    /**
     * 国付宝私钥存放地址
     */
    @Value("${gopay.private.key.path}")
    private String privateKeyPath;

    /**
     * 网联公钥存放地址
     */
    @Value("${nucc.public.key.path}")
    private String publicKeyPath;


    /** 
     * 签名 
     * @param base
     * @return
     * @throws GopayException
     * @author zhoutong
     */
    public NuccBaseMessage sign(BaseMessage base) throws GopayException {
        NuccBaseMessage message = (NuccBaseMessage) base;
        try {            
            XStream xstream = new XStream();
            StringBuffer returnStr = new StringBuffer();
            xstream.autodetectAnnotations(true);
            xstream.aliasSystemAttribute(null, "class");
            String xmlStr = xstream.toXML(message);
            returnStr.append(XML_HEADER);
            returnStr.append("\r\n");
            returnStr.append(xmlStr);
            String plainMsg = returnStr.toString();
            message.setPlainMessage(plainMsg);
            logger.info("nucc send message before sign: " + LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(message)));
            byte[] base64SingDataBytes = CertificateCoder.sign(xmlStr,  privateKeyPath, "SHA256withRSA");
            String signMessage ="{S:"+Base64.encodeBase64String(base64SingDataBytes)+"}";
            message.setSignMessage(signMessage);
            logger.info("nucc send message after sign: " + LoggerMaskUtils.maskString(ToStringBuilder.reflectionToString(message)));
        }  catch (Exception e) {
            logger.error("nucc sign error：", e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6126);
        }
        return message;
        
    }
    

    /**
     * 验签 
     * @param res
     * @param resCla
     * @param resCla
     * @return
     * @throws GopayException
     * @author zhoutong
     */
    public Object verify(String res,Class resCla) throws GopayException {
        boolean flag;
        String plainMsg;
        String signMsg;
        try{
            int indexPStart = res.indexOf("<root");
            int indexPEnd = res.indexOf("</root>");
            int indexSStart = res.indexOf("{S:");
            int indexSEnd = res.indexOf("}");
            if(indexPStart > -1 && indexPEnd > -1 && indexSStart > -1 && indexSEnd > -1){
                plainMsg = res.substring(indexPStart,indexPEnd+7);
                signMsg = res.substring(indexSStart+3,indexSEnd);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6127);
            }
            flag= CertificateCoder.verify(plainMsg, signMsg, publicKeyPath);
            if(flag){
                XStream xstream = new XStream();
                xstream.ignoreUnknownElements();
                xstream.autodetectAnnotations(true);
                xstream.processAnnotations(resCla);
                return xstream.fromXML(plainMsg);
            }else{
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E6127);
            }            
        }catch(Exception ex){
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6127,ex.getMessage());
        }
    }

    public NuccBaseMessage certEncryptBcdl(NuccBaseMessage message) throws GopayException{
        String key = AesEncryptUtils.getRandomString(32);
        NuccBaseHeaderMessage header= message.getMsgHeader();
        NuccBcdlBodyReq body= (NuccBcdlBodyReq) message.getMsgBody();
        NuccBcdlBodyPyerInf pyerInf = body.getPyerInf();
        NuccBcdlBodyPyeeAcctInf pyeeInf = body.getPyeeAcctInf();
        try {
            String pyerAcctNo =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(pyerInf.getPyerAcctNo(), key));
            pyerInf.setPyerAcctNo(pyerAcctNo);
            String pyerAcctNm =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(pyerInf.getPyerAcctNm(), key));
            pyerInf.setPyerAcctNm(pyerAcctNm);
            String pyeeBkNo =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(pyeeInf.getPyeeBkNo(), key));
            pyeeInf.setPyeeBkNo(pyeeBkNo);
            String pyeeBkNm =Base64.encodeBase64String(AesEncryptUtils.Aes256Encode(pyeeInf.getPyeeBkNm(), key));
            pyeeInf.setPyeeBkNm(pyeeBkNm);
            key = "01|"+key;
            String dgtlEnvlp = Base64.encodeBase64String(CertificateCoder.encryptByPublicKey(key,publicKeyPath));
            header.setDgtlEnvlp(dgtlEnvlp);
        } catch (Exception e) {
            BankLogUtils.printExPayExceptionLog(message, e);
            throw new GopayException(ProcCodeConstants.PROC_CODE_100E6045);
        }
        return message;
    }
}
